package com.woniu.smart.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

/**
 * @Description: TODO
 * @Author: WangHeng
 * @Date: 2022/10/24 17:56
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private AccessDeniedHandler  accessDeniedHandler;
    @Autowired
    private LogoutSuccessHandler logoutSuccessHandler;
    @Bean
    LoginAuthenticationSuccessHandler loginAuthenticationSuccessHandler(){
        return new LoginAuthenticationSuccessHandler();
    }
    @Bean
    LoginAuthenticationFailureHandler loginAuthenticationFailureHandler(){
        return new LoginAuthenticationFailureHandler();
    }
    @Bean
    JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter(){
        return new JwtAuthenticationTokenFilter();
    }
    @Bean
    LoginFilter loginFilter() throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        //指定AuthenticationManager，注意不是上面带bean的方法
        loginFilter.setAuthenticationManager(authenticationManager());
        //登录成功的处理
        loginFilter.setAuthenticationSuccessHandler(loginAuthenticationSuccessHandler());
        //登录失败的处理
        loginFilter.setAuthenticationFailureHandler(loginAuthenticationFailureHandler());
        return loginFilter;
    }
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        // CRSF禁用，不使用session
        httpSecurity.csrf().disable();
        //允许跨域
        httpSecurity.cors();
        // 基于token，所以不需要session
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        //403未授权的异常处理
        httpSecurity.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
        // 过滤请求
        httpSecurity.authorizeRequests()
                .antMatchers("/admins/login").permitAll()//注意不能使用.anonymous(),否则登录成功再点登录时一直提示403
                .antMatchers(
                        HttpMethod.GET,
                        "/admins/**"
                ).permitAll()
                .antMatchers(
                        HttpMethod.GET,
                        "/*.html",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js"
                ).permitAll()
                .antMatchers("/swagger-ui/**","/api/**").anonymous()
                .antMatchers("/swagger-resources/**").anonymous()
                .antMatchers("/*/api-docs").anonymous()
                .anyRequest().authenticated();
        // 添加loginFilter,在UsernamePasswordAuthenticationFilter过滤器所在位置替换
        httpSecurity.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
        //在UsernamePasswordAuthenticationFilter过滤器之前执行
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(),UsernamePasswordAuthenticationFilter.class);
        //配置退出成功的处理类
        httpSecurity.logout().logoutSuccessHandler(logoutSuccessHandler);
        // 修改jwtAuthenticationTokenFilter在` LogoutFilter`之前执行，不然会出现空指针
        httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), LogoutFilter.class);
    }
    @Bean
    public PasswordEncoder passwordEncoder() {
        // 这里我们使用bcrypt加密算法，安全性比较高
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
}
